package de.parsemis.strategy;

import static de.parsemis.miner.environment.Debug.VERBOSE;
import static de.parsemis.miner.environment.Debug.VVERBOSE;
import static de.parsemis.miner.environment.Debug.VVVERBOSE;
import static de.parsemis.miner.environment.Debug.out;

import java.util.Collection;
import java.util.Iterator;

import de.parsemis.algorithms.Algorithm;
import de.parsemis.miner.chain.SearchLatticeNode;
import de.parsemis.miner.environment.LocalEnvironment;
import de.parsemis.miner.general.Fragment;
import de.parsemis.utils.Frequented;

public class RecursivePatternStrategy<NodeType, EdgeType> extends
		RecursiveStrategy<NodeType, EdgeType> {

	public Collection<Fragment<NodeType, EdgeType>> search(
			final Algorithm<NodeType, EdgeType> algo) {
		ret = LocalEnvironment.env(this).getReturnSet();
		extender = algo.getExtender(0);
		final long begin_time = System.currentTimeMillis();
		
		for (final Iterator<SearchLatticeNode<NodeType, EdgeType>> it = algo.initialNodes(); it.hasNext();) {
			final SearchLatticeNode<NodeType, EdgeType> code = it.next();
			final long time = System.currentTimeMillis();
			if (VERBOSE) {
				out.print("doing seed " + code + " ...");
			}

			searchPattern(code);
			it.remove();

			if (VERBOSE) {
				out.println("\tdone (" + (System.currentTimeMillis() - time)
						+ " ms)");
			}
		}
		
		if (VERBOSE) {
			out.println("\n#################################################\n" +
					" pattern search all done in ("
					+ (System.currentTimeMillis() - begin_time)
					+ " ms)\n##################################################");
		}
		return ret;
		
	}
	
	@SuppressWarnings("unchecked")
	private void search(final SearchLatticeNode<NodeType, EdgeType> node) {

		final Collection<SearchLatticeNode<NodeType, EdgeType>> tmp = extender.getChildren(node);

		for (final SearchLatticeNode<NodeType, EdgeType> child : tmp) {
			if (VVVERBOSE) {
				out.println("doing " + child);
			}
			//out.println("doing " + child);
			search(child);

		}

		if (VVERBOSE) {
			out.println("node " + node + " done. Store: " + node.store()
					+ " children " + tmp.size() + " freq "
					+ ((Frequented) node).frequency());
		}

		if (node.store()) {
			node.store(ret);
		} else {
			node.release();
		}

		node.finalizeIt();
	}
	
	private void searchPattern(final SearchLatticeNode<NodeType, EdgeType> node) {

		final Collection<SearchLatticeNode<NodeType, EdgeType>> tmp = extender.getChildren(node);

		for (final SearchLatticeNode<NodeType, EdgeType> child : tmp) {
			if (VVVERBOSE) {
				System.out.println("\n--------------------LEVEL "
						+ child.getLevel()
						+ "-----------------------");
				out.println("doing " + child);
			}
			searchPattern(child);
			
			//child.release();
			//child.finalizeIt();
		}
		
/*		if (VVERBOSE) {
			out.println("node " + node + " done. Store: " + node.store()
					+ " children " + tmp.size() + " freq "
					+ ((Frequented) node).frequency());
		}*/
		
		if (node.store()) {
			node.store(ret);
		} else {
			node.release();
		}

		node.finalizeIt();
	}
}
